﻿RequestsApp.service('SharePointJSOMService', function ($q, $rootScope) {
    var spItemToRequest = function (spListItem) {
        var request = new Request();
        request.Id = spListItem.ID;
        request.City = spListItem.City;
        request.Company = spListItem.Company;
        request.Details = spListItem.Details;

        request.Orders = spListItem.Orders;
        request.Approvers = (spListItem.Approvers && spListItem.Approvers.results) ? spListItem.Approvers.results : [];
        request.Travelers = (spListItem.Travelers && spListItem.Travelers.results) ? spListItem.Travelers.results : [];

        request.Country = (spListItem.Country && spListItem.Country.results) ? spListItem.Country.results : [];
        request.Purpose = (spListItem.Purpose && spListItem.Purpose.results) ? spListItem.Purpose.results : [];
        request.FinYear = (spListItem.FinYear && spListItem.FinYear.results) ? spListItem.FinYear.results : [];
        request.Training = (spListItem.Training && spListItem.Training.results) ? spListItem.Training.results : [];
        return request;
    };

    var requestToSPItem = function(request, spListItem, context, list) {
        spListItem.set_item('City', request.City);
        spListItem.set_item('Company', request.Company);
        spListItem.set_item('Details', request.Details);
        //#region training
        var trainingField = list.get_fields().getByInternalNameOrTitle("Training");
        var trainingTaxonomyField = context.castTo(trainingField, SP.Taxonomy.TaxonomyField);
        var trainings = [];
        $.each(request.Training, function(k, c) {
            trainings.push('-1;#' + c.Label + '|' + c.TermGuid);
        });
        console.log(trainings.join(';#'));
        var trainingTerms = new SP.Taxonomy.TaxonomyFieldValueCollection(context, trainings.join(';#'), trainingTaxonomyField);
        trainingTaxonomyField.setFieldValueByValueCollection(spListItem, trainingTerms);
        //#endregion
        //#region finyear
        var finyearField = list.get_fields().getByInternalNameOrTitle("FinYear");
        var finyearTaxonomyField = context.castTo(finyearField, SP.Taxonomy.TaxonomyField);
        var finyears = [];
        $.each(request.FinYear, function (k, c) {
            finyears.push('-1;#' + c.Label + '|' + c.TermGuid);
        });
        var finyearTerms = new SP.Taxonomy.TaxonomyFieldValueCollection(context, finyears.join(';#'), finyearTaxonomyField);
        finyearTaxonomyField.setFieldValueByValueCollection(spListItem, finyearTerms);
        //#endregion
        //#region purpose
        var purposeField = list.get_fields().getByInternalNameOrTitle("Purpose");
        var purposeTaxonomyField = context.castTo(purposeField, SP.Taxonomy.TaxonomyField);
        var purposes = [];
        $.each(request.Purpose, function (k, c) {
            purposes.push('-1;#' + c.Label + '|' + c.TermGuid);
        });
        var porposeTerms = new SP.Taxonomy.TaxonomyFieldValueCollection(context, purposes.join(';#'), purposeTaxonomyField);
        purposeTaxonomyField.setFieldValueByValueCollection(spListItem, porposeTerms);
        //#endregion
        //#region country
        var countryField = list.get_fields().getByInternalNameOrTitle("Country");
        var countryTaxonomyField = context.castTo(countryField, SP.Taxonomy.TaxonomyField);
        var countries = [];
        $.each(request.Country, function (k, c) {
            countries.push('-1;#' + c.Label + '|' + c.TermGuid);
        });
        var countryTerms = new SP.Taxonomy.TaxonomyFieldValueCollection(context, countries.join(';#'), countryTaxonomyField);
        countryTaxonomyField.setFieldValueByValueCollection(spListItem, countryTerms);
        //#endregion
        //#region approvers
        var approvers = [];
        $.each(request.Approvers, function (k, v) {
            approvers.push(SP.FieldUserValue.fromUser(v.Name));
        });
        spListItem.set_item('Approvers', approvers);
        //#endregion
        //#region travelers
        var travelers = [];
        $.each(request.Travelers, function (k, v) {
            travelers.push(SP.FieldUserValue.fromUser(v.Name));
        });
        spListItem.set_item('Travelers', travelers);
        //#endregion
        return spListItem;
    };

    this.getRequests = function () {
        var deferred = $q.defer();
        var select = "ID,Details,Training,FinYear,Purpose,Country,Company,City,Travelers/Name,Travelers/Title,Approvers/Name,Approvers/Title";
        var expand = "Travelers,Approvers";
        var restQueryUrl = String.format("{0}/_api/SP.AppContextSite(@target)/web/lists/getByTitle('{1}')/items?$select={2}&$expand={3}&@target='{4}'",
            $rootScope.AppWebUrl,
            $rootScope.RequestsListName,
            select,
            expand,
            $rootScope.HostWebUrl);

        var executor = new SP.RequestExecutor($rootScope.AppWebUrl);
        executor.executeAsync({
            url: restQueryUrl,
            method: "GET",
            headers: { "Accept": "application/json; odata=verbose" },
            success: function (data, textStatus, xhr) {
                var results = JSON.parse(data.body).d.results;
                var requests = [];
                angular.forEach(results, function (result) {
                    requests.push(spItemToRequest(result));
                });
                $rootScope.$apply(function(){
                    deferred.resolve(requests);
                });
            },
            error: function (xhr, textStatus, errorThrown) {
                $rootScope.$apply(function () {
                    deferred.reject(JSON.stringify(xhr));
                });
            }
        });
        return deferred.promise;
    };

    this.getRequest = function (requestId) {
        var deferred = $q.defer();

        var select = "ID,Details,Training,FinYear,Purpose,Country,Company,City,Travelers/Name,Travelers/Title,Approvers/Name,Approvers/Title";
        var expand = "Travelers,Approvers";
        var restQueryUrl = String.format("{0}/_api/SP.AppContextSite(@target)/web/lists/getByTitle('{1}')/items({2})?$select={3}&$expand={4}&@target='{5}'",
            $rootScope.AppWebUrl,
            $rootScope.RequestsListName,
            requestId,
            select,
            expand,
            $rootScope.HostWebUrl);

        var executor = new SP.RequestExecutor($rootScope.AppWebUrl);
        executor.executeAsync({
            url: restQueryUrl,
            method: "GET",
            headers: { "Accept": "application/json; odata=verbose" },
            success: function (data, textStatus, xhr) {
                $rootScope.$apply(function () {
                    deferred.resolve(spItemToRequest(JSON.parse(data.body).d));
                });
            },
            error: function (xhr, textStatus, errorThrown) {
                $rootScope.$apply(function () {
                    deferred.reject(JSON.stringify(xhr));
                });
            }
        });
        return deferred.promise;
    };

    this.deleteRequest = function (id) {
        var deferred = $q.defer();

        var context = new SP.ClientContext($rootScope.AppWebUrl);
        var appContextSite = new SP.AppContextSite(context, $rootScope.HostWebUrl);
        var web = appContextSite.get_web();
        context.load(web);
        var list = web.get_lists().getByTitle($rootScope.RequestsListName);

        var listItem = list.getItemById(id);
        listItem.deleteObject();
        context.executeQueryAsync(
                Function.createDelegate(this, function () {
                    $rootScope.$apply(function () {
                        deferred.resolve(id);
                    });
                }),
                Function.createDelegate(this, function () {
                    $rootScope.$apply(function () {
                        deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
                    });
                })
            );
        return deferred.promise;
    };

    this.addRequest = function (request) {
        var deferred = $q.defer();
        var context = new SP.ClientContext($rootScope.AppWebUrl);
        var appContextSite = new SP.AppContextSite(context, $rootScope.HostWebUrl);
        var web = appContextSite.get_web();
        var list = web.get_lists().getByTitle($rootScope.RequestsListName);

        var listItemInfo = new SP.ListItemCreationInformation();
        var listItem = list.addItem(listItemInfo);
        requestToSPItem(request, listItem, context, list);
        listItem.update();

        context.executeQueryAsync(
            function () {
                var id = listItem.get_id();
                $rootScope.$apply(function () {
                    deferred.resolve(id);
                });
            },
            function (sender, args) {
                $rootScope.$apply(function () {
                    deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
                });
            }
        );

        return deferred.promise;
    };

    this.updateRequest = function (request) {
        var deferred = $q.defer();

        var context = new SP.ClientContext($rootScope.AppWebUrl);
        var appContextSite = new SP.AppContextSite(context, $rootScope.HostWebUrl);
        var web = appContextSite.get_web();
        var list = web.get_lists().getByTitle($rootScope.RequestsListName);
        var listItem = list.getItemById(request.Id);
        requestToSPItem(request, listItem, context, list);
        listItem.update();

        context.executeQueryAsync(
            Function.createDelegate(this, function (sender, args) {
                $rootScope.$apply(function () {
                    deferred.resolve(request.Id);
                });
            }),
            Function.createDelegate(this, function (sender, args) {
                $rootScope.$apply(function () {
                    deferred.reject(args.get_message() + "\n" + args.get_stackTrace());
                });
            })
        );
        return deferred.promise;
    };

    this.getRequestTaxonomyFieldsProperties = function(){
        var deferred = $q.defer();

        var loadTaxonomyField = function (context, fieldName) {
            var field = list.get_fields().getByInternalNameOrTitle(fieldName);
            context.load(field);
            var taxonomy = context.castTo(field, SP.Taxonomy.TaxonomyField);
            context.load(taxonomy);
            return taxonomy;
        }

        var toTaxonomyObject = function (serviceResult){
            return {
                TermSetId: serviceResult.get_termSetId().toString(),
                Multiple: serviceResult.get_allowMultipleValues(),
                Required: serviceResult.get_required()
            }
        }

        var context = new SP.ClientContext($rootScope.AppWebUrl);
        var site = new SP.AppContextSite(context, $rootScope.HostWebUrl);
        var web = site.get_web();
        context.load(web);
        var list = web.get_lists().getByTitle($rootScope.RequestsListName);
        context.load(list);

        var countryField = loadTaxonomyField(context, 'Country');
        var purposeField = loadTaxonomyField(context, 'Purpose');
        var finYearField = loadTaxonomyField(context, 'FinYear');
        var trainingField = loadTaxonomyField(context, 'Training');

        context.executeQueryAsync(Function.createDelegate(this, function () {
            try {
                $rootScope.$apply(function () {
                    deferred.resolve({
                        Country: toTaxonomyObject(countryField),
                        Purpose: toTaxonomyObject(purposeField),
                        FinYear: toTaxonomyObject(finYearField),
                        Training: toTaxonomyObject(trainingField)
                    });
                });
            } catch (ex) {
                $rootScope.$apply(function () {
                    deferred.reject("name: " + ex.name + "\nmessage: " + ex.message);
                });
            }
        }), Function.createDelegate(this, function (sender, args) {
            $rootScope.$apply(function () {
                deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
            });
        }));
        return deferred.promise;
    }
});